#pragma once

#include "Common.hpp"
#include "Socket.hpp"
#include "Log.hpp"

using namespace SocketModule;
using namespace LogModule;

// client请求消息格式
// 1 + 1
class Request
{
public:
    // 构造函数1
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }

    // 构造函数2, 无参构造函数
    Request() {}

    // 序列化函数
    std::string Serialize()
    {
        // 创建Json对象
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;              // 创建Json写入器
        std::string ret = writer.write(root); // json写入字符串
        return ret;
    }

    // 反序列化函数
    bool Deserialize(std::string &in)
    {
        Json::Value root;    // 创建Json对象
        Json::Reader reader; // 创建Json读取器

        bool ret = reader.parse(in, root); // json字符串解析到root
        if (ret)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ret;
    }

    int GetX() { return _x; } // 获取_x成员

    int GetY() { return _y; } // 获取_y成员

    char GetOper() { return _oper; } // 获取_oper成员

    // 析构函数
    ~Request() {}

private:
    int _x;
    int _y;
    char _oper; // 运算符号
};

// server响应消息格式
class Response
{
public:
    // 构造函数0
    Response() {}

    // 构造函数1
    Response(int result, int code) : _result(result), _code(code)
    {
    }

    // 序列化函数
    std::string Serialize()
    {
        // 创建Json对象
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        // 创建Json写入器
        Json::FastWriter writer;
        return writer.write(root);
    }

    // 反序列化函数
    bool Deserialize(std::string &in)
    {
        Json::Value root;    // 创建Json对象
        Json::Reader reader; // 创建Json读取器

        bool ret = reader.parse(in, root); // json字符串解析到root
        if (ret)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ret;
    }

    // 客户端显示计算结果
    void ShowResult()
    {
        std::cout << "计算结果为: " << _result << "[" << _code << "]" << std::endl;
    }

    void SetResult(int ret) { _result = ret; } // 设置运算结果
    void SetCode(int code) { _code = code; }   // 设置退出码

    // 析构函数
    ~Response() {}

private:
    int _result; // 运算结果
    int _code;   // 退出码, 0表示成功, 1, 2, 3...表示不同类型失败
};

const std::string sep = "\r\n";                       // 默认分隔符
using func_t = std::function<Response(Request &req)>; // 运算函数类型

// 协议类
class Protocol
{
public:
    // 构造函数0
    Protocol() {}

    // 构造函数1
    Protocol(func_t f) : _func(f)
    {
    }

    // 编码函数, 对报文串添加报头s
    // 10\r\n{"_x":10, "_y":20, "_oper":1}\r\n
    std::string Encode(std::string &in)
    {
        std::string len = std::to_string(in.size()); // 计算报文长度
        return len + sep + in + sep;                 // 添加报头
    }

    // 解码函数, 解析报文串, 得到报文内容
    // 10\r\n{"_x":10, "_y":20, "_oper":1}\r\n10\r\n{"_x":10, "_y":20, "_oper":1}\r\n
    bool Decode(std::string &buffer, std::string *package)
    {
        LOG(LogLevel::DEBUG) << "enter protocol decode";

        // 查找第一个分隔符
        ssize_t pos = buffer.find(sep);
        if (pos == std::string::npos)
        {
            return false; // 未找到分隔符, 说明还没收到完整报头
        }

        // 根据pos截取报文长度
        std::string package_len_str = buffer.substr(0, pos); // 报文长度, 字符串型
        int package_len_int = std::stoi(package_len_str);    // 报文长度, 整数型

        // 截取报文内容, 检查报文内容是否完整
        int target_len = package_len_str.size() + package_len_int + 2 * sep.size(); // 报头+报文完整长度
        if (buffer.size() < target_len)
        {
            return false; // 报文长度不足, 说明报文内容还没收全
        }

        *package = buffer.substr(pos + sep.size(), package_len_int); // 获取报文内容, {"_x":10, "_y":20, "_oper":1}

        buffer.erase(0, target_len); // 删除已解析的完整报文

        return true; // 解析成功
    }

    // 获取客户端request消息
    std::string Execute(std::string &package)
    {
        LOG(LogLevel::DEBUG) << "enter Protocol::Execute begin"; // 打印测试日志

        Request req;
        int ret2 = req.Deserialize(package); // 反序列化package到req
        if (!ret2)
            return std::string(); // 报文格式有误, 反序列化失败, 停止调用

        // 对Req进行相应业务处理, 得到返回值resp
        Response resp = _func(req);

        // 序列化resp, 得到返回报文json_str
        std::string json_str = resp.Serialize();

        // 编码json_str, 得到返回报文send_str
        std::string send_str = Encode(json_str);

        LOG(LogLevel::DEBUG) << "enter Protocol::Execute end"; // 打印测试日志

        return send_str; // 返回报文send_str  
    }

    // 客户端获取server回复
    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buffer, Response *resp)
    {
        // 获取返回报文

        while (1)
        {
            int ret = client->Recv(&resp_buffer);
            if (ret > 0)
            {
                // 接收成功
                // 1. 解析报文
                std::string json_package;
                bool n = Decode(resp_buffer, &json_package);
                if (!n)
                {
                    // 报文解析失败, 内容不全或格式错误, 忽略该报文
                    continue;
                }

                // 2. 反序列化json_package到Response
                resp->Deserialize(json_package); // 反序列化json_package到resp

                return true; // 解析成功, 得到完整的Response
            }
            else if (ret == 0)
            {
                // 服务器出错
                std::cout << "server quit, 服务器出错!" << std::endl;
                return false; // 解析失败, 服务器出错
            }
            else
            {
                // 接收失败
                std::cout << "recv error, 接收失败!" << std::endl;
                return false; // 解析失败, 接收失败
            }
        }
    }

    // 创建请求
    // std::string BuildRequestString(int x, int y, char oper)
    // {
    //     // 1. 创建Request对象
    //     Request req(x, y, oper);
    //     // 2. 序列化Request对象, 得到json_req
    //     std::string json_req = req.Serialize();
    //     /* std::cout << "-----------------json_req: --------------------" << std::endl;
    //     std::cout << json_req << std::endl; */
    //     // 3. 编码json_req, 得到添加报头的send_str并返回
    //     return Encode(json_req);
    // }

    // 析构函数
    ~Protocol() {}

private:
    func_t _func; // 运算函数
};